package org.goose.web;

import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.goose.web.annotations.Controller;
import org.goose.web.annotations.RequestMapping;
import org.goose.web.controllers.OrderController;

public class HandlerMap {
	private final static Logger logger = Logger
			.getLogger(OrderController.class);
	private static HandlerMap HANDLER_MAP = null;
	
	private static Map<String, Handler> handlers = null;
	
	private HandlerMap(){
		HANDLER_MAP = this;
		handlers = new HashMap<String, Handler>();
		
		//1. Retrieve .java files
		List<String> list = new ArrayList<String>();
		list = getClasses(list, new File("./src/main/java/org/goose/web/controllers"));
		
		//2. Filter out those annotated by @Controller
		@SuppressWarnings("rawtypes")
		List<Class> controllers = new ArrayList<Class>();
		for(String s : list){
			Class<?> c;
			try {
				c = Class.forName("org.goose.web.controllers."+s);
				if(c.getAnnotation(Controller.class) != null) 
					controllers.add(c);
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		//3. List their @RequestMapping-methods
		for(Class<?> c: controllers){
			Method[] methods = c.getMethods();
			for(Method m : methods){
				if(m.getAnnotation(RequestMapping.class) != null){
					try {
						handlers.put(m.getAnnotation(RequestMapping.class).method()+":"+m.getAnnotation(RequestMapping.class).value(), 
								new Handler(m, c.newInstance()));
					} catch (InstantiationException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					logger.info("Found RequestMapping: "+m.getName());
				}
			}
		}
		
	}
	
	private List<String> getClasses(List<String> list, File file){
		File[] files = file.listFiles();
		for(File f : files){
			if(f.isDirectory()){
				getClasses(list, f);
			}else if(f.getName().endsWith(".java")){
				list.add(f.getName().substring(0, f.getName().length()-5));
			}
		}
		
		return list;
	}
	
	public static Handler getHandler(String requestPath, int requestMethod, Map pathVariables){
		// 0. Split requestPath
		String[] rPath = requestPath.split("/");
		//for(String rS: rPath) System.out.println("rPath: "+rS);
		
		// 1. Loop all handler-keys
		for(String key : handlers.keySet()){
			// 1.1 Split key
			String[] methodKey = key.split(":");
			int method = Integer.parseInt(methodKey[0]);
			String[] path = methodKey[1].split("/");
			
			//System.out.println("Method: "+method);
			//for(String s : path) System.out.println("Path: "+s);
			
			// 2. Compare requested- with known-key
			// 2.1 Compare variable-count
			if(rPath.length == path.length && requestMethod == method){
				//2.2 Compare each path-segment
				boolean correct = true;
				for(int i = 0; i < path.length; i++){
					String s1 = path[i];
					String s2 = rPath[i];
					if(s1.length() > 0){
						if(s1.equals(s2) || s1.charAt(0) == '{'){
							if(s1.charAt(0) == '{') pathVariables.put(s1.substring(1, s1.length()-1), s2);
						}else{
							correct = false;
							break;
						}
					}
				}
				if(correct){
					logger.info("Handler found: "+key);
					return handlers.get(key);
				}
			}
		}
		
		return null;
//		System.out.println("Looking for RequestMapping: '"+method+":"+path+"'");
//		Handler h = handlers.get(method+":"+path);
//		if(h==null) System.out.println("No handler found for: '"+method+":"+path+"'");
//		return h;
	}
	
	public static void init(){
		new HandlerMap();
	}
}
